package com.boot.security.service.authorization;

import cn.hutool.core.collection.CollectionUtil;
import com.boot.security.model.bo.Authority;
import com.boot.security.model.bo.TokenAuthentication;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.AuthorizationServiceException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description 判断用户是否拥有权限
 * @date 2020/2/23 18:06
 **/

public class TokenAccessDecisionVoter implements AccessDecisionVoter<Object> {

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return attribute instanceof Authority;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    @Override
    public int vote(Authentication auth, Object object, Collection<ConfigAttribute> attributes) {
        if (auth instanceof TokenAuthentication
                && supports(object.getClass())) {
            TokenAuthentication authentication = (TokenAuthentication) auth;

            for (ConfigAttribute attribute : attributes) {
                if (!supports(attribute)) {
                    return ACCESS_ABSTAIN;
                }
            }

            List<String> userAuthorities = authentication.getAuthorities().stream()
                    .map(GrantedAuthority::getAuthority)
                    .collect(Collectors.toList());

            List<String> resourceAuthorities = attributes.stream()
                    .map(ConfigAttribute::getAttribute)
                    .collect(Collectors.toList());

            if (CollectionUtil.containsAll(userAuthorities, resourceAuthorities)) {
                return ACCESS_GRANTED;
            } else {
                Collection<String> intersection = CollectionUtil.intersection(userAuthorities, resourceAuthorities);
                Collection<String> disjunction = CollectionUtil.disjunction(resourceAuthorities, intersection);
                throw new AuthorizationServiceException("缺少权限: " + disjunction.toString());
            }
        } else {
            return ACCESS_ABSTAIN;
        }
    }
}
